package es.mgil.whoWantsToBeAMillonaire.activities;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import es.mgil.whoWantsToBeAMillonaire.R;
import es.mgil.whoWantsToBeAMillonaire.dialogs.CancelDialog;
import es.mgil.whoWantsToBeAMillonaire.dialogs.FinishDialog;
import es.mgil.whoWantsToBeAMillonaire.dialogs.ShouldContinueDialog;
import es.mgil.whoWantsToBeAMillonaire.runnables.ResponseProgressBarRunnable;
import es.mgil.whoWantsToBeAMillonaire.util.MillonaireDatabaseHelper;
import es.mgil.whoWantsToBeAMillonaire.util.MusicManager;
import es.mgil.whoWantsToBeAMillonaire.util.PreferencesKeys;
import es.mgil.whoWantsToBeAMillonaire.util.Question;
import es.mgil.whoWantsToBeAMillonaire.util.Utils;

public class Play extends FragmentActivity implements OnCompletionListener {
	public static final int STYLE_VISIBLE = 1;
	public static final int STYLE_INVISIBLE = 2;

	public static final int STYLE_CLICKABLE = 1;
	public static final int STYLE_NO_CLICKABLE = 2;

	public static final int STYLE_COLOR_NORMAL = 1;
	public static final int STYLE_COLOR_SELECTED = 2;
	public static final int STYLE_COLOR_PROPOSED = 3;
	public static final int STYLE_COLOR_RIGHT = 4;
	public static final int STYLE_COLOR_FAIL = 5;

	private TextView playFor;
	private TextView questionNumber;
	private TextView question;
	private List<TextView> textViews;
	public ProgressBar progressBar;

	private List<Integer> awards;
	private List<Question> questions;
	private Question currentQuestion;

	public SharedPreferences preferences;
	public Editor editor;
	private int lastOrientation;

	public ResponseProgressBarRunnable runnable;

	public MusicManager mmBack;
	private MusicManager mmNewQuestion;
	public MusicManager mmWinQuestion;
	public MusicManager mmFailQuestion;
	public MusicManager mmWinGame;

	public MillonaireDatabaseHelper dbHelper;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.layout_play);

		// store the preferences
		preferences = getSharedPreferences(PreferencesKeys.SHARED_PREFERENCES,
				MODE_PRIVATE);
		editor = preferences.edit();

		// store the current orientation
		lastOrientation = getResources().getConfiguration().orientation;

		// get a database helper
		dbHelper = new MillonaireDatabaseHelper(this);

		// initialize some useful objects from interface
		playFor = (TextView) findViewById(R.id.play_textView_playFor);
		questionNumber = (TextView) findViewById(R.id.play_textView_question_number);
		question = (TextView) findViewById(R.id.play_textView_question);

		textViews = new ArrayList<TextView>();
		textViews.add((TextView) findViewById(R.id.play_answer_A));
		textViews.add((TextView) findViewById(R.id.play_answer_B));
		textViews.add((TextView) findViewById(R.id.play_answer_C));
		textViews.add((TextView) findViewById(R.id.play_answer_D));
		progressBar = (ProgressBar) findViewById(R.id.play_progressBar_ForResponse);
		progressBar.setMax(preferences.getInt(
				PreferencesKeys.PREFERENCES_SECONDS, 30));

		// initialize the runnable for the questions
		runnable = new ResponseProgressBarRunnable(this);

		// initialize the list of awards
		awards = Utils.fillAwards();

		// load questions. Can throw any controlled exception, changing the
		// content view in that case
		loadQuestions();

		// initialize the music manager for current activity
		mmBack = MusicManager.getInstance(R.raw.back, null, true);
		mmNewQuestion = MusicManager.getInstance(R.raw.new_question, this,
				false);
		mmWinQuestion = MusicManager.getInstance(R.raw.win_question, this,
				false);
		mmFailQuestion = MusicManager.getInstance(R.raw.fail_question, this,
				false);
		mmWinGame = MusicManager.getInstance(R.raw.win_game, null, false);
	}

	@Override
	protected void onResume() {
		if (questions != null && !questions.isEmpty()) {
			// if have any question (no error loading the app)...
			if (MusicManager.isMusicEnabled(preferences)) {
				// if music enabled, start playing back music
				mmBack.startPlayer(this);
			} else {
				// if not, stop it
				mmBack.stopPlayer();
			}

			// prepare next question. Next question will be the first question
			// if the activity is first launched, or the last being answered if
			// onPause is called previously
			prepareNextQuestion();

			// set the listener to the music players again due to the activity
			// is created every time it's resumed
			mmNewQuestion.setOnCompletionListener(this);
			mmWinQuestion.setOnCompletionListener(this);
			mmFailQuestion.setOnCompletionListener(this);
		}

		super.onResume();
	}

	@Override
	protected void onPause() {
		int orientation = getResources().getConfiguration().orientation;
		if (lastOrientation != orientation) {
			// if onPause is called due to an orientation change, do nothing
			lastOrientation = orientation;
			runnable.cancelLopping();
		} else {
			// in other case (i.e. application change...), pause or stop the
			// music if it's enabled
			runnable.noState();
			if (MusicManager.isMusicEnabled(preferences)) {
				if (mmBack.isPlaying()) {
					mmBack.pausePlayer();
				}
				if (mmNewQuestion.isPlaying()) {
					mmNewQuestion.stopPlayer();
				}
				if (mmWinQuestion.isPlaying()) {
					mmWinQuestion.stopPlayer();
				}
				if (mmFailQuestion.isPlaying()) {
					mmFailQuestion.stopPlayer();
				}
				if (mmWinGame.isPlaying()) {
					mmWinGame.stopPlayer();
				}
			}
		}

		super.onPause();
	}

	@Override
	public void onCompletion(MediaPlayer mp) {
		// this method is called every time a media player (with listener)
		// finishes its playing
		if (mp.equals(mmNewQuestion.getPlayer())) {
			// if media player for new question is finished, show the answers
			// and start the runnable counting down for the response
			showAnswers();
			runnable.startLooping();
			mmBack.startPlayer(Play.this);
		} else if (mp.equals(mmWinQuestion.getPlayer())) {
			// if media player for won question is finished, shown a dialog
			// asking to continue with next question or not
			ShouldContinueDialog dialog3 = new ShouldContinueDialog();
			dialog3.show(getSupportFragmentManager(),
					ShouldContinueDialog.CONTINUE_DIALOG_ID);
		} else if (mp.equals(mmFailQuestion.getPlayer())) {
			// if media player for filed question is finished, shown a dialog
			// with the indication that no score is get
			FinishDialog dialog2 = new FinishDialog();
			dialog2.show(getSupportFragmentManager(),
					FinishDialog.FINISH_DIALOG_ID);
		}
	}

	@Override
	public void finish() {
		// closes the database if opened
		dbHelper.close();

		// when finish the activity, destroy all the media players for this
		// activity
		mmBack.destroy();
		mmNewQuestion.destroy();
		mmWinQuestion.destroy();
		mmFailQuestion.destroy();
		mmWinGame.destroy();

		super.finish();
	}

	@Override
	public void onBackPressed() {
		// when cabk key is pressed...
		if (preferences.getBoolean(PreferencesKeys.PREFERENCES_ERROR, false)) {
			// ... we can directly treat it as normally we do when the activity
			// is opened with errors (can't read questions from XML)
			super.onBackPressed();
		} else {
			// ... or if we're playing it, we show a dialog in order to ask the
			// user if exit or not. In that case, no score will is get
			CancelDialog dialog = new CancelDialog();
			dialog.show(getSupportFragmentManager(),
					CancelDialog.CANCEL_DIALOG_ID);
		}
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		if (preferences.getInt(PreferencesKeys.PREFERENCES_SELECTED_ANSWER, -1) != -1) {
			// if an answer is selected, don't show the menu
			return false;
		} else {
			// if no answer is selected, then show the menu. Show only the not
			// used items
			if (preferences.getBoolean(
					PreferencesKeys.PREFERENCES_PHONE_REMOVED, false)) {
				menu.removeItem(R.id.menu_play_phone);
			}
			if (preferences.getBoolean(
					PreferencesKeys.PREFERENCES_PERCENT_REMOVED, false)) {
				menu.removeItem(R.id.menu_play_percent);
			}
			if (preferences.getBoolean(
					PreferencesKeys.PREFERENCES_AUDIENCE_REMOVED, false)) {
				menu.removeItem(R.id.menu_play_audience);
			}
		}

		return super.onPrepareOptionsMenu(menu);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.menu_play, menu);
		return true;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_play_phone:
			usePhoneHelp();
			return true;
		case R.id.menu_play_percent:
			usePercentHelp();
			return true;
		case R.id.menu_play_audience:
			useAudienceHelp();
			return true;
		default:
			return super.onMenuItemSelected(featureId, item);
		}
	}

	/**
	 * Load the questions. If any error occurs, the content view is changed to
	 * inform it
	 */
	private boolean loadQuestions() {
		try {
			XmlPullParser parser = getResources().getXml(R.xml.questions);
			questions = Utils.getQuestionsList(parser);
			if (questions != null && !questions.isEmpty()) {
				return true;
			} else {
				// any error while filling the questions???
				setErrorContents(R.string.play_error_filling_questions);
				return false;
			}
		} catch (FileNotFoundException e) {
			// any error while looking for the file???
			setErrorContents(R.string.play_error_reading_questions);
			return false;
		} catch (IOException e) {
			// any error while opening the file???
			setErrorContents(R.string.play_error_reading_questions);
			return false;
		} catch (XmlPullParserException e) {
			// any error while parsing the XML file???
			setErrorContents(R.string.play_error_filling_questions);
			return false;
		}
	}

	/**
	 * Set the error content view to the activity
	 */
	private void setErrorContents(int messageResource) {
		setContentView(R.layout.layout_error);
		TextView error = (TextView) findViewById(R.id.TextViewError);
		error.setText(messageResource);

		// save the state of error for the activity
		editor.putBoolean(PreferencesKeys.PREFERENCES_ERROR, true);
		editor.commit();
	}

	/**
	 * Prepare the layout for the next question
	 */
	public void prepareNextQuestion() {
		// get current question number
		int currentQuestionNumber = preferences.getInt(
				PreferencesKeys.PREFERENCES_QUESTION_NUMBER, 1);
		currentQuestion = questions.get(currentQuestionNumber - 1);

		// set the text for awards and question number
		playFor.setText(awards.get(currentQuestionNumber)
				+ getResources().getString(R.string.play_award_currency));
		questionNumber.setText("" + (currentQuestionNumber));

		// set the text of the question
		question.setText(currentQuestion.getText());

		// set progress bar progress with the value places in preferences
		progressBar.setProgress(preferences.getInt(
				PreferencesKeys.PREFERENCES_PROGRESS_BAR_PROGRESS, 0));

		// set the text of the answers
		textViews.get(0).setText("A: " + currentQuestion.getAnswer1());
		textViews.get(1).setText("B: " + currentQuestion.getAnswer2());
		textViews.get(2).setText("C: " + currentQuestion.getAnswer3());
		textViews.get(3).setText("D: " + currentQuestion.getAnswer4());

		// refresh the IU with the corresponding states of every answer
		refreshAllAnswersState();

		// different performance depending on music is enabled or not...
		if (MusicManager.isMusicEnabled(preferences)) {
			// ... if enabled, we will show first the question, start an
			// introduction music and when this music is finished, the answers
			// will be displayed

			// first we get the state of the activity in order to not to
			// reproduce once and again the sound when it's being played and we
			// change the orientation
			boolean isPlaying = preferences.getBoolean(
					PreferencesKeys.PREFERENCES_QUESTION_MUSIC_PLAYING, false);
			if (!isPlaying) {
				// if it's not playing the music, we will present the new
				// question: only the question
				presentNewQuestion();
			} else {
				// else, we will start the count down directly
				runnable.startLooping();
			}
		} else {
			// ... if music id disabled, directly show the full question and
			// answers
			runnable.startLooping();
		}
	}

	/**
	 * Present the new question. Hide answers, stop background music and start
	 * new question music
	 */
	private void presentNewQuestion() {
		// set the current state of the activity, playing the music to present
		// the new question
		editor.putBoolean(PreferencesKeys.PREFERENCES_QUESTION_MUSIC_PLAYING,
				true);
		editor.commit();

		// hide the answers
		hideAnswers();

		if (mmBack.isPlaying()) {
			// stop playing the background music
			mmBack.stopPlayer();
		}

		// and start playing the new question music
		mmNewQuestion.startPlayer(this);
	}

	/**
	 * Hide all the answers
	 */
	private void hideAnswers() {
		for (TextView tv : textViews) {
			tv.setVisibility(View.INVISIBLE);
		}
	}

	/**
	 * Show all the answers
	 */
	private void showAnswers() {
		for (TextView tv : textViews) {
			tv.setVisibility(View.VISIBLE);
		}
	}

	/**
	 * Refresh the state of every answer: if they're clickable or not, if
	 * they're visible or not and theirs background color
	 */
	public void refreshAllAnswersState() {
		// set the style of the 4 answers
		for (TextView textView : textViews) {
			// get visibitily for current text view from preferences
			int styleVisible = preferences.getInt(
					String.valueOf(textView.getId())
							+ PreferencesKeys.PREFERENCES_VISIBLE,
					STYLE_VISIBLE);
			// get 'clickability' for current text view from preferences
			int styleClickable = preferences.getInt(
					String.valueOf(textView.getId())
							+ PreferencesKeys.PREFERENCES_CLICKABLE,
					STYLE_CLICKABLE);
			// get background color for current text view from preferences
			int styleColor = preferences.getInt(
					String.valueOf(textView.getId())
							+ PreferencesKeys.PREFERENCES_COLOR,
					STYLE_COLOR_NORMAL);

			// set visibility
			if (styleVisible == STYLE_VISIBLE) {
				textView.setVisibility(View.VISIBLE);
			} else if (styleVisible == STYLE_INVISIBLE) {
				textView.setVisibility(View.INVISIBLE);
			}

			// set 'clickability'
			if (styleClickable == STYLE_CLICKABLE) {
				textView.setClickable(true);
			} else if (styleClickable == STYLE_NO_CLICKABLE) {
				textView.setClickable(false);
			}

			// set background color
			if (styleColor == STYLE_COLOR_SELECTED) {
				textView.setBackgroundResource(R.drawable.background_blue);
			} else if (styleColor == STYLE_COLOR_PROPOSED) {
				textView.setBackgroundResource(R.drawable.background_orange);
			} else if (styleColor == STYLE_COLOR_RIGHT) {
				textView.setBackgroundResource(R.drawable.background_green);
			} else if (styleColor == STYLE_COLOR_FAIL) {
				textView.setBackgroundResource(R.drawable.background_red);
			} else if (styleColor == STYLE_COLOR_NORMAL) {
				textView.setBackgroundResource(R.drawable.background_black);
			}
		}
	}

	/**
	 * Function for answer click
	 */
	public void clickAnswer(View view) {
		// prevent multiple touch in the answers
		if (preferences.getInt(PreferencesKeys.PREFERENCES_SELECTED_ANSWER, -1) != -1) {
			return;
		}

		// make blue chose answer
		editor.putInt(String.valueOf(view.getId())
				+ PreferencesKeys.PREFERENCES_COLOR, STYLE_COLOR_SELECTED);

		// make no clickable all answers
		for (TextView textView : textViews) {
			editor.putInt(String.valueOf(textView.getId())
					+ PreferencesKeys.PREFERENCES_CLICKABLE, STYLE_NO_CLICKABLE);
			if (textView.equals(view)) {
				editor.putInt(PreferencesKeys.PREFERENCES_SELECTED_ANSWER,
						textView.getId());
			}
		}
		editor.commit();

		// refresh the answers state
		refreshAllAnswersState();

		// mark the runnable state as answer selected
		runnable.answered();
	}

	/**
	 * Function to indicate that phone help is used
	 */
	private void usePhoneHelp() {
		String phone = currentQuestion.getAnswerFromNumber(currentQuestion
				.getPhone());

		// mark corresponding text views as possible answers
		for (TextView textView : textViews) {
			if (textView.getText().toString().contains(phone)) {
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_VISIBLE, STYLE_VISIBLE);
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_CLICKABLE,
						STYLE_CLICKABLE);
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_COLOR,
						STYLE_COLOR_PROPOSED);
			}
		}

		// mark this help as used and to be removed for following questions
		editor.putBoolean(PreferencesKeys.PREFERENCES_PHONE_REMOVED, true);
		editor.putBoolean(PreferencesKeys.PREFERENCES_PHONE_USED, true);
		editor.commit();

		// refresh the answers state
		refreshAllAnswersState();
	}

	/**
	 * Function to indicate that percent help is used
	 */
	private void usePercentHelp() {
		String first = currentQuestion.getAnswerFromNumber(currentQuestion
				.getFifty1());
		String second = currentQuestion.getAnswerFromNumber(currentQuestion
				.getFifty2());

		// mark corresponding text views as possible answers
		for (TextView textView : textViews) {
			if (textView.getText().toString().contains(first)
					|| textView.getText().toString().contains(second)) {
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_VISIBLE, STYLE_INVISIBLE);
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_CLICKABLE,
						STYLE_NO_CLICKABLE);
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_COLOR, STYLE_COLOR_NORMAL);
			}
		}

		// mark this help as used and to be removed for following questions
		editor.putBoolean(PreferencesKeys.PREFERENCES_PERCENT_REMOVED, true);
		editor.putBoolean(PreferencesKeys.PREFERENCES_PERCENT_USED, true);
		editor.commit();

		// refresh the answers state
		refreshAllAnswersState();
	}

	private void useAudienceHelp() {
		String audience = currentQuestion.getAnswerFromNumber(currentQuestion
				.getAudience());

		// mark corresponding text views as possible answers
		for (TextView textView : textViews) {
			if (textView.getText().toString().contains(audience)) {
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_VISIBLE, STYLE_VISIBLE);
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_CLICKABLE,
						STYLE_CLICKABLE);
				editor.putInt(String.valueOf(textView.getId())
						+ PreferencesKeys.PREFERENCES_COLOR,
						STYLE_COLOR_PROPOSED);
			}
		}

		// mark this help as used and to be removed for following questions
		editor.putBoolean(PreferencesKeys.PREFERENCES_AUDIENCE_REMOVED, true);
		editor.putBoolean(PreferencesKeys.PREFERENCES_AUDIENCE_USED, true);
		editor.commit();

		// refresh the answers state
		refreshAllAnswersState();
	}

	/**
	 * Get final award depending on the last question answered played
	 */
	public int getFinalAward() {
		int currentQuestionNumber = preferences.getInt(
				PreferencesKeys.PREFERENCES_QUESTION_NUMBER, 1);

		if (currentQuestionNumber > 10) {
			return awards.get(10);
		} else if (currentQuestionNumber > 5) {
			return awards.get(5);
		} else {
			return 0;
		}
	}

	/**
	 * Reset the answer state from preferences
	 */
	public void resetAnswersState() {
		for (TextView textView : textViews) {
			editor.remove(String.valueOf(textView.getId())
					+ PreferencesKeys.PREFERENCES_VISIBLE);
			editor.remove(String.valueOf(textView.getId())
					+ PreferencesKeys.PREFERENCES_CLICKABLE);
			editor.remove(String.valueOf(textView.getId())
					+ PreferencesKeys.PREFERENCES_COLOR);
			editor.commit();
		}
	}

	/**
	 * Get the list of awards
	 */
	public List<Integer> getAwards() {
		return awards;
	}

	/**
	 * Get the list of Questions
	 */
	public List<Question> getQuestions() {
		return questions;
	}

	/**
	 * Get current Question
	 */
	public Question getCurrentQuestion() {
		return currentQuestion;
	}

	/**
	 * Get list of text views
	 */
	public List<TextView> getTextViews() {
		return textViews;
	}

}
